package com.teach.controller;

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.teach.config.AliPayConfig;
import com.teach.dto.AliPay;
import com.teach.dto.ResponseEntityDto;
import com.teach.entity.TbOrder;
import com.teach.entity.TbOrderReturn;
import com.teach.mapper.TbOrderMapper;
import com.teach.mapper.TbOrderReturnMapper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;

// xjlugv6874@sandbox.com
// 9428521.24 - 30 = 9428491.24 + 30 = 9428521.24
@RestController
@RequestMapping("/alipay")
@Api(tags = "订单接口")
@Slf4j
public class AliPayController {

    public static final String GATEWAY_URL = "https://openapi.alipaydev.com/gateway.do";
    private static final String FORMAT = "JSON";
    private static final String CHARSET = "UTF-8";
    //签名方式
    private static final String SIGN_TYPE = "RSA2";

    @Resource
    private AliPayConfig aliPayConfig;

    @Resource
    private TbOrderMapper tbOrderMapper;


    @Resource
    private TbOrderReturnMapper tbOrderReturnMapper;

    Logger logger = LogManager.getLogger(AliPayController.class);//实例log日志对象

    /**
     *
     * @param orderNo     订单号
     * @param httpResponse 响应
     * @throws Exception
     */
    @GetMapping("/pay") // &subject=xxx&traceNo=xxx&totalAmount=xxx
    @ApiOperation("支付")
    public void pay(@RequestParam("orderNo")String orderNo, HttpServletResponse httpResponse) throws Exception {
         LambdaQueryWrapper<TbOrder> eq = new LambdaQueryWrapper<TbOrder>()
                .eq(TbOrder::getOrderNumber, orderNo);
         TbOrder order = tbOrderMapper.selectOne(eq);

        // 1. 创建Client，通用SDK提供的Client，负责调用支付宝的API
        AlipayClient alipayClient = new DefaultAlipayClient(
                GATEWAY_URL,
                aliPayConfig.getAppId(),
                aliPayConfig.getAppPrivateKey(),
                FORMAT,
                CHARSET,
                aliPayConfig.getAlipayPublicKey(),
                SIGN_TYPE);

        // 2. 创建 Request并设置Request参数
        AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();  // 发送请求的 Request类
        request.setNotifyUrl(aliPayConfig.getNotifyUrl());
        JSONObject bizContent = new JSONObject();
        bizContent.put("out_trade_no", order.getOrderNumber());  // 我们自己生成的订单编号
        bizContent.put("total_amount", order.getPrice()); // 订单的总金额
        bizContent.put("subject", order.getName());   // 支付的名称
        bizContent.put("product_code", "FAST_INSTANT_TRADE_PAY");  // 固定配置
        request.setBizContent(bizContent.toString());

        // 执行请求，拿到响应的结果，返回给浏览器
        String form = "";
        try {
            form = alipayClient.pageExecute(request).getBody(); // 调用SDK生成表单
        } catch (AlipayApiException e) {
            logger.error("支付出错:"+e.getMessage());
            e.printStackTrace();
        }
        httpResponse.setContentType("text/html;charset=" + CHARSET);
        httpResponse.getWriter().write(form);// 直接将完整的表单html输出到页面
        httpResponse.getWriter().flush();
        httpResponse.getWriter().close();
    }

    @PostMapping("/notify")  // 注意这里必须是POST接口
    @ApiOperation("支付成功回调")
    public String payNotify(HttpServletRequest request) throws Exception {
        try {
            if (request.getParameter("trade_status").equals("TRADE_SUCCESS")) {
                System.out.println("=========支付宝异步回调========");

                Map<String, String> params = new HashMap<>();
                Map<String, String[]> requestParams = request.getParameterMap();
                for (String name : requestParams.keySet()) {
                    params.put(name, request.getParameter(name));
                }

                String tradeNo = params.get("out_trade_no");//订单号
                String gmtPayment = params.get("gmt_payment");//支付时间
                String alipayTradeNo = params.get("trade_no");//支付宝流水号
                String sign = params.get("sign");//签名


                String content = AlipaySignature.getSignCheckContentV1(params);//通用SDK的一个类
                boolean checkSignature = AlipaySignature.rsa256CheckContent(content, sign, aliPayConfig.getAlipayPublicKey(), "UTF-8"); // 验证签名

                // 支付宝验签
                if (checkSignature) {
                    // 验签通过
                    System.out.println("交易名称: " + params.get("subject"));
                    System.out.println("交易状态: " + params.get("trade_status"));
                    System.out.println("支付宝交易凭证号: " + params.get("trade_no"));
                    System.out.println("商户订单号: " + params.get("out_trade_no"));
                    System.out.println("交易金额: " + params.get("total_amount"));
                    System.out.println("买家在支付宝唯一id: " + params.get("buyer_id"));
                    System.out.println("买家付款时间: " + params.get("gmt_payment"));
                    System.out.println("买家付款金额: " + params.get("buyer_pay_amount"));

                    // 更新订单已支付
                     LambdaUpdateWrapper<TbOrder> set = new LambdaUpdateWrapper<TbOrder>()
                            .eq(TbOrder::getOrderNumber, tradeNo)
                             .set(TbOrder::getPayTime,gmtPayment)
                             .set(TbOrder::getSerialNum,alipayTradeNo)
                            .set(TbOrder::getPayState, 2);
                    tbOrderMapper.update(null,set);
                    System.out.println("支付成功");
                }
            }
            return "success";
        } catch (AlipayApiException e) {
            logger.error("支付出错:"+e.getMessage());
            throw new RuntimeException(e);
        }
    }

    /**
     *
     * @param aliPay  订单信息
     * @return
     * @throws AlipayApiException
     */
    @GetMapping("/return")
    @ApiOperation("七天无理由退款接口")
    public ResponseEntityDto returnPay(AliPay aliPay) throws AlipayApiException {
        try {
            if (aliPay==null){
                return new ResponseEntityDto();
            }
            // 7天无理由退款，获取当前时间
            String now = DateUtil.now();
            Wrapper<TbOrder> query=new LambdaQueryWrapper<TbOrder>()
                    .eq(TbOrder::getOrderNumber,aliPay.getTraceNo());
            TbOrder tbOrder = tbOrderMapper.selectOne(query);
            if (tbOrder != null) {
                // hutool工具类，判断时间间隔
                long between = DateUtil
                        .between(DateUtil.parseDateTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(
                                tbOrder.getPayTime())),
                                DateUtil.parseDateTime(DateUtil.now()),
                                DateUnit.DAY);

                if (between > 7) {
                    return new ResponseEntityDto(null,5000,"时间过期",false);
                }

            }
            // 1. 创建Client，通用SDK提供的Client，负责调用支付宝的API
            AlipayClient alipayClient = new DefaultAlipayClient(GATEWAY_URL,
                    aliPayConfig.getAppId(), aliPayConfig.getAppPrivateKey(), FORMAT, CHARSET,
                    aliPayConfig.getAlipayPublicKey(), SIGN_TYPE);
            // 2. 创建 Request，设置参数
            AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
            JSONObject bizContent = new JSONObject();
            bizContent.put("trade_no", aliPay.getAlipayTraceNo());  // 支付宝回调的订单流水号
            bizContent.put("refund_amount", aliPay.getTotalAmount());  // 订单的总金额
            bizContent.put("out_request_no", aliPay.getTraceNo());   //  我的订单编号
            request.setBizContent(bizContent.toString());

            // 3. 执行请求
            AlipayTradeRefundResponse response = alipayClient.execute(request);
            if (response.isSuccess()) {  // 退款成功，isSuccess 为true
                System.out.println("调用成功");
                // 4. 更新数据库状态
                LambdaUpdateWrapper<TbOrder> set = new LambdaUpdateWrapper<TbOrder>()
                        .eq(TbOrder::getOrderNumber, aliPay.getTraceNo())
                        .set(TbOrder::getPayState, 4);
                tbOrderMapper.update(null,set);//修改状态为退款
                //生成退款表
                TbOrderReturn tbOrderReturn=new TbOrderReturn()
                        .setReturnName(tbOrder.getName())
                        .setOrderId(tbOrder.getId())
                        .setReturnSerial(tbOrder.getSerialNum())
                        .setReturnPrice(tbOrder.getPrice().doubleValue());
                tbOrderReturnMapper.insert(tbOrderReturn);
                return new ResponseEntityDto(null,2000,"退款成功",true);
            } else {   // 退款失败，isSuccess 为false

                System.out.println(response.getBody());
                return new ResponseEntityDto(null,5000,"未知原因退款失败",false);
            }
        } catch (AlipayApiException e) {
            logger.error("支付出错:"+e.getMessage());
            throw new RuntimeException(e);
        }


    }

}

